/************************************************************
 * Project Name         [Thinking_In_Java]
 * File Name            [CalculatorMain.java]
 * Creation Date        [10-Jul-2014]
 * 
 * Copyright© ge.y.yang@gmail.com All Rights Reserved
 * 
 * Work hard, play harder, think big and keep fit
 ************************************************************/
package pkg_02_gui.calculator_V1;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.math.BigDecimal;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingConstants;

/**
 * 一个计算器, 与Windows自带计算器的标准版的功能, 界面相仿, 但不支持界面操作<br>
 * CE和C键的区别, CE只清除最后一次输入的数字, C则将所有设置初始化
 * 
 * @author 不落的太阳(Sean Yang)
 * @version 1.0
 * @since JDK 6
 * 
 */
public class CalculatorMain extends JFrame implements ActionListener {

	private static final long serialVersionUID = 2549758863653267716L;

	// 获得屏幕的宽和高
	private static final int WIDTH = Toolkit.getDefaultToolkit()
			.getScreenSize().width;
	private static final int HEIGHT = Toolkit.getDefaultToolkit()
			.getScreenSize().height;

	// 标志用户按下的是否为整个表达式的第一个数字, 或者是运算符后的第一个数字
	private boolean firstDigit = true;

	// 计算的中间结果
	private double tempResult = 0.0;

	// 操作是否合法
	private boolean isLegalOperation = true;

	// 当前的运算符号
	private String currentOperator = "=";

	// 计算器面板
	private CalculatorPanel calcPanel = null;

	// 计算器的文本框
	private final JTextField resultField = new JTextField("0");

	public CalculatorMain() {
		// 设置计算器结果文本框为右对齐方式
		resultField.setHorizontalAlignment(SwingConstants.RIGHT);
		resultField.setEditable(false);
		resultField.setBackground(Color.GRAY);
		JPanel textPanel = new JPanel();
		textPanel.setLayout(new BorderLayout());
		textPanel.add("North", resultField);

		calcPanel = new CalculatorPanel(this);
		this.add("North", resultField);
		this.add("Center", calcPanel);

		setBackground(Color.LIGHT_GRAY);
		setTitle("计算器");
		this.setLocation(WIDTH / 2, HEIGHT / 2);
		setResizable(false);
		pack();
		setVisible(true);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
	}

	/**
	 * 处理事件
	 */
	@Override
	public void actionPerformed(ActionEvent e) {
		String label = e.getActionCommand();
		if (label.equals("Backspace")) {
			handleBackspace();
		} else if (label.equals("CE")) {
			handleCE();
		} else if (label.equals("C")) {
			handleC();
		} else if ("0123456789.".indexOf(label) >= 0) {
			handleNumber(label);
		} else {
			handleOperator(label);
		}
	}

	/**
	 * 初始化计算器
	 */
	private void initCalculator() {
		resultField.setText("0");
		firstDigit = true;
		currentOperator = "=";
	}

	/**
	 * 处理退格键
	 */
	private void handleBackspace() {
		String text = resultField.getText();
		int textLength = text.length();
		if (textLength > 0) {
			// 将文本的最后一个字符去掉
			text = text.substring(0, textLength - 1);
			// 如果截取后文本无内容, 则初始化计算器各项值, 否则显示新内容
			if (text.length() == 0) {
				initCalculator();
			} else {
				resultField.setText(text);
			}
		}
	}

	/**
	 * 处理CE键
	 */
	private void handleCE() {
		resultField.setText("0");
	}

	/**
	 * 处理C键
	 */
	private void handleC() {
		initCalculator();
	}

	/**
	 * 处理数字
	 * 
	 * @param label
	 */
	private void handleNumber(String label) {
		// 输入的第一个数字
		if (firstDigit) {
			resultField.setText(label);
		} else if (label.equals(".")
				&& (resultField.getText().indexOf(".") < 0)) {
			// 输入的是小数点且之前未输入小数点, 则将小数点追加在文本的后面
			resultField.setText(resultField.getText() + ".");
		} else if (!label.equals(".")) {
			// 如果输入的不是小数点, 则将数字附在结果文本框的后面
			resultField.setText(resultField.getText() + label);
		}
		// 以后输入的数字不再是第一个数字, 因此将其置为false
		firstDigit = false;
	}

	/**
	 * 处理运算符被按下的事件
	 * 
	 * 注意: 第一次输入数字时, 运算符currentOperator="="
	 * 
	 * @param label
	 */
	private void handleOperator(String label) {
		if (currentOperator.equals("=")) {// 等号
			tempResult = getNumberFromTextField();
		} else if (currentOperator.equals("+")) { // 加法运算
			tempResult += getNumberFromTextField();
		} else if (currentOperator.equals("-")) { // 减法运算
			BigDecimal decimal1 = new BigDecimal("" + tempResult);
			BigDecimal decimal2 = new BigDecimal(resultField.getText());
			tempResult = decimal1.subtract(decimal2).doubleValue();
		} else if (currentOperator.equals("*")) {// 乘法运算
			tempResult *= getNumberFromTextField();
		} else if (currentOperator.equals("/")) { // 除法运算
			// 除法运算考虑除数为0的情况
			if (getNumberFromTextField() == 0) {
				isLegalOperation = false;
				resultField.setText("除数不能为零");
			} else {
				tempResult /= getNumberFromTextField();
			}
		} else if (currentOperator.equals("1/x")) { // 倒数运算
			if (getNumberFromTextField() == 0) {
				isLegalOperation = false;
				resultField.setText("零没有倒数");
			} else {
				tempResult = 1 / tempResult;
			}
		} else if (currentOperator.equals("sqrt")) { // 平方根运算
			tempResult = Math.sqrt(tempResult);
		} else if (currentOperator.equals("%")) {// 百分号运算
			tempResult = tempResult / 100;
		} else if (currentOperator.equals("+/-")) {// 取反运算
			tempResult = tempResult * (-1);
		}

		// 如果是整数, 显示的时候去掉0
		if (isLegalOperation) {
			long temp1 = 0;
			double temp2 = 0;
			temp1 = (long) tempResult;
			temp2 = tempResult - temp1;
			if (temp2 == 0) {
				resultField.setText(String.valueOf(temp1));
			} else {
				resultField.setText(String.valueOf(tempResult));
			}
		}
		currentOperator = label;
		firstDigit = true;
		isLegalOperation = true;
	}

	private double getNumberFromTextField() {
		double result = 0;
		try {
			result = Double.valueOf(resultField.getText()).doubleValue();
		} catch (NumberFormatException e) {
		}
		return result;
	}

	/**
	 * 测试方法
	 * 
	 * @param args
	 *            命令行参数
	 */
	public static void main(String[] args) {
		EventQueue.invokeLater(new Runnable() {
			@Override
			public void run() {
				new CalculatorMain();
			}
		});

	}
}
